package noth.li.sgs.hero;

import noth.li.sgs.card.BasicCard;
import noth.li.sgs.card.HolderCard;
import noth.li.sgs.card.equipment.ArmorCard;
import noth.li.sgs.card.equipment.HorseCard;
import noth.li.sgs.card.equipment.WeaponCard;
import noth.li.sgs.card.jinNang.YanShiJinNangCard;
import noth.li.sgs.exception.BaseException;
import noth.li.sgs.utils.CommonUtil;

import java.util.*;

/**
 * 武将类基类
 */
public abstract class BaseHero {

    protected String name; //姓名
    protected int maxLife; //最大体力值
    protected int life; //体力值
    protected String power; //势力
    protected String sex; //性别
    protected int maxSha = 1; //最大出杀数
    protected int shaCount = 0; //出牌阶段出杀的个数
    protected int getCardsCount = 2; //每回合摸牌阶段摸的牌
    protected int useWinesCount = 0; //武将使用酒的个数
    protected int position; //武将场上的位置

    protected LinkedList<HolderCard> holdCards = new LinkedList<>(); //手牌
    protected Stack<YanShiJinNangCard> yanShiArea = new Stack<>(); //判定区

    protected WeaponCard weapon; //武器区
    protected ArmorCard armor; //防具区
    /**
     * horses[0] --- +1马
     * horses[1] --- 进攻马
     */
    protected HorseCard[] horses = new HorseCard[2]; //坐骑区

    protected boolean lbssFlg = false; //乐不思蜀判定标志
    protected boolean blcdFlg = false; //兵粮寸断判定标志


    public BaseHero(String name, int maxLife, int life, String power, String sex) {
        this.name = name;
        this.maxLife = maxLife;
        this.life = life;
        this.power = power;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMaxLife() {
        return maxLife;
    }

    public void setMaxLife(int maxLife) {
        this.maxLife = maxLife;
    }

    public int getLife() {
        return life;
    }

    public void setLife(int life) {
        this.life = life;
    }

    public String getPower() {
        return power;
    }

    public void setPower(String power) {
        this.power = power;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public LinkedList<HolderCard> getHoldCards() {
        return holdCards;
    }

    public void setHoldCards(LinkedList<HolderCard> holdCards) {
        this.holdCards = holdCards;
    }

    public Stack<YanShiJinNangCard> getYanShiArea() {
        return yanShiArea;
    }

    public void setYanShiArea(Stack<YanShiJinNangCard> yanShiArea) {
        this.yanShiArea = yanShiArea;
    }

    public WeaponCard getWeapon() {
        return weapon;
    }

    public void setWeapon(WeaponCard weapon) {
        this.weapon = weapon;
    }

    public ArmorCard getArmor() {
        return armor;
    }

    public void setArmor(ArmorCard armor) {
        this.armor = armor;
    }

    public HorseCard[] getHorses() {
        return horses;
    }

    public void setHorses(HorseCard[] horses) {
        this.horses = horses;
    }

    public int getMaxSha() {
        return maxSha;
    }

    public void setMaxSha(int maxSha) {
        this.maxSha = maxSha;
    }

    public int getShaCount() {
        return shaCount;
    }

    public void setShaCount(int shaCount) {
        this.shaCount = shaCount;
    }

    public int getGetCardsCount() {
        return getCardsCount;
    }

    public void setGetCardsCount(int getCardsCount) {
        this.getCardsCount = getCardsCount;
    }

    public int getUseWinesCount() {
        return useWinesCount;
    }

    public void setUseWinesCount(int useWinesCount) {
        this.useWinesCount = useWinesCount;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

    @Override
    public String toString() {
        return this.power + "-" + this.name + "体力值:" + this.maxLife + "当前体力值:" + this.life;
    }

    /**
     * 接收牌的方法，武将可通过此方法增加自己的手牌数
     *
     * @param cards 接收的手牌集合
     */
    public void acceptCards(List<HolderCard> cards) throws BaseException {
        if (cards == null || cards.size() == 0)
            throw new BaseException("接收的手牌不能为空!");
        try {
            cards.stream().forEach(item -> {
                acceptCards(item);
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 接收牌的方法，武将可通过此方法增加自己的手牌数
     *
     * @param card 接收的手牌
     */

    public void acceptCards(HolderCard card) {
        this.holdCards.add(card);
    }

    /**
     * 武将被杀的方法
     *
     * @param other      杀的来源
     * @param aliveHeros 场上存活的武将
     * @param sc         字符输入流
     * @param throwCards 弃牌堆
     * @param bc         使用的杀
     */
    public void beiSha(BaseHero other, List<BaseHero> aliveHeros, Scanner sc, LinkedList<HolderCard> throwCards, HolderCard bc) throws BaseException {
        if (CommonUtil.isEmpty(other))
            throw new BaseException("杀的来源不能为空");

        System.out.println(other.name + "对" + this.name + "使用" + bc);

        //武将的手牌数不为空的话，可以选择是否用闪抵消杀的效果
        boolean shanFlg = this.hasShans();

        //如果有闪,询问是否使用闪抵消杀的效果
        if (shanFlg) {
            while (true) {
                System.out.print(this.name + "是否出闪抵消" + other.name + "的杀?(0-不闪,1-闪):");
                String an = sc.nextLine();
                if (!("0".equals(an) || "1".equals(an))) {
                    System.out.println("请输入正确的操作!");
                    continue;
                }
                if ("1".equals(an)) {//出闪
                    HolderCard useCard = CommonUtil.checkCardMessage(sc, this, "闪");
                    if (CommonUtil.isNotEmpty(useCard)) {
                        this.holdCards.remove(useCard);
                        throwCards.add(useCard);
                        System.out.println(this.name + "对" + other.name + "出闪...");
                        other.getHoldCards().remove(bc);
                        throwCards.add(bc);

                        //如果杀来源的武将装备了贯石斧,可以发动贯石斧
                        if (CommonUtil.isNotEmpty(other.getWeapon()) && "贯石斧".equals(other.getWeapon())) {
                            //计算身上牌的数量,如果数量够2,则可以发动贯石斧技能,强制命中(除贯石斧自身外)
                            int cardCount = other.getHoldCards().size();
                            if (CommonUtil.isNotEmpty(other.armor))
                                cardCount++;
                            if (CommonUtil.isNotEmpty(other.horses))
                                cardCount += other.horses.length;

                            if (cardCount >= 2) {
                                System.out.println(this.name + "可以弃置两张牌(除贯石斧),使" + bc + "强制命中...");

                                boolean useGsf = false;

                                while (true) {
                                    System.out.print(this.name + "是否发动贯石斧?(0-发动,1-不发动):");
                                    an = sc.nextLine();
                                    if (!("0".equals(an) || "1".equals(an))) {
                                        System.out.println("请输入正确的操作!");
                                        continue;
                                    }
                                    break;
                                }
                                if ("0".equals(an))
                                    useGsf = true;

                                //发动贯石斧,使此杀强制命中
                                if (useGsf) {
                                    int throwsCount = 0;

                                    System.out.println(this.name + "可弃置的牌如下");
                                    //展示所有可以弃置的牌
                                    LinkedList<HolderCard> allCards = new LinkedList<>(other.getHoldCards());
                                    allCards.add(other.getArmor());
                                    allCards.addAll(Arrays.asList(other.getHorses()));

                                    System.out.println("可弃置的牌==>" + CommonUtil.showCardsName(allCards));


                                }
                            }
                        }

                        //使用酒出杀后,不管有没有出闪，武将的使用酒的个数都将被清零
                        other.setUseWinesCount(0);
                        return;
                    }
                } else {//不出
                    break;
                }
            }
        }

        beiShaRemoveLife(bc, other, throwCards, aliveHeros, sc);
    }


    /**
     * 武将被杀后执行的一系列操作
     *
     * @param bc         使武将掉血的基本牌
     * @param other      出杀的武将
     * @param throwCards 弃牌堆
     * @param aliveHeros 场上存活的武将
     * @param sc         交互对象
     */
    protected void beiShaRemoveLife(HolderCard bc, BaseHero other, List<HolderCard> throwCards, List<BaseHero> aliveHeros, Scanner sc) {

        //发动武器技能
        int huoShaCount = 0;
        if (CommonUtil.isNotEmpty(other.weapon))
            huoShaCount = (int) CommonUtil.weaponFunction(other.getWeapon(), other, this, bc, sc, throwCards);

        this.takeDamage(1 + other.getUseWinesCount() + huoShaCount, aliveHeros, sc, throwCards);
        //使用酒出杀后,武将的使用酒的个数清零
        other.setUseWinesCount(0);
        other.getHoldCards().remove(bc);
        throwCards.add(bc);
    }

    /**
     * 武将受到伤害的方法，通常有些武将受伤后，会调用此方法执行对应操作
     *
     * @param damage     武将受到的伤害
     * @param aliveHeros 场上存活的武将
     * @param sc         字符输入流
     * @param throwCards 弃牌堆
     */
    public void takeDamage(int damage, List<BaseHero> aliveHeros, Scanner sc, List<HolderCard> throwCards) {
        this.life -= damage;
        System.out.println(this.name + "受到了" + damage + "点伤害," + "当前体力值为" + this.life);
        if (this.life <= 0) {
            System.out.println(this.name + "进入了濒死状态...");
            //询问自己有没有酒或桃
            boolean needPeach = this.aliveMySelf(sc, throwCards);

            boolean isAlive = false; //武将是否存活 默认死亡
            //询问他人是否有桃
            if (!needPeach) {
                for (BaseHero h : aliveHeros) {
                    //只要有一个人救援,则武将存活
                    if (this.name != h.getName())
                        isAlive = h.aliveOther(this, sc, throwCards);
                }
            } else {
                isAlive = true;
            }

            if (!isAlive) {
                System.out.println(this.name + "体力值为0...退出游戏");
                throwCards.addAll(this.getHoldCards());
                throwCards.addAll(this.getYanShiArea());
                throwCards.addAll(Arrays.asList(this.getHorses()));
                throwCards.add(this.getWeapon());
                throwCards.add(this.getArmor());
                aliveHeros.remove(this);
            }
            if (aliveHeros.size() == 1) {
                System.out.println(aliveHeros.get(0).getName() + "获得胜利!");
                System.exit(0);
            }
        }
    }

    /**
     * 将其他武将脱离濒死状态的方法
     *
     * @param other      需要救援的武将
     * @param sc         玩家交互操作
     * @param throwCards 弃牌堆
     * @return true-玩家存活 false-玩家死亡
     */
    protected boolean aliveOther(BaseHero other, Scanner sc, List<HolderCard> throwCards) {

        if (!(this.hasPeaches())) {
            System.out.println(other.getName() + "没有足够的桃来救援...");
            return false;
        }

        //询问他人是否有桃
        System.out.println(other.name + "进入濒死状态,是否救援?");
        System.out.println("1表示救援，2表示不救援...");

        String answer = ""; //玩家的回答
        do {
            System.out.print("请输入您的选择:");
            answer = sc.nextLine();
        } while (!(answer.equals("1") || answer.equals("2")));

        if (!answer.equals("1"))
            return false;

        do {
            System.out.println(other.name + "当前体力值为" + other.life + ",还需要" + (1 - other.life) + "个桃" + "是否使用桃帮" + other.name + "解除濒死状态?");
            String cardNum = ""; //用户输入的牌的代表
            while (true) {
                if (!(this.hasPeaches())) {
                    System.out.println(this.name + "没有足够的桃");
                    break;
                }

                HolderCard useCard = CommonUtil.checkCardMessage(sc, this, "桃");

                other.life++;
                System.out.println(other.name + "回复了1点体力...");
                this.holdCards.remove(useCard);
                throwCards.add(useCard);

                if (this.life <= 0) {
                    System.out.println(other.name + "当前体力为" + other.life + ",还需要" + (1 - other.life) + "个桃");
                    continue;
                } else {
                    System.out.println(other.name + "脱离了濒死状态");
                    break;
                }
            }
        } while (this.hasPeaches() || this.hasWines());
        return !(other.life <= 0);
    }

    /**
     * 将自己脱离濒死状态的方法
     *
     * @param sc         玩家交互操作
     * @param throwCards 弃牌堆
     * @return true-不需要别人救援 false-需要别人救援
     */
    protected boolean aliveMySelf(Scanner sc, List<HolderCard> throwCards) {
        do {
            System.out.println(this.name + "当前体力值为" + this.life + ",还需要" + (1 - this.life) + "个桃或酒" + "是否使用桃帮" + this.name + "解除濒死状态?");
            int wineCount = 0; //进入濒死状态最多每次使用一次酒
            while (true) {
                if (!(this.hasPeaches() || this.hasWines())) {
                    System.out.println(this.name + "没有足够的桃或酒");
                    break;
                }

                HolderCard useCard = CommonUtil.checkCardMessage(sc, this, "桃,酒");

                this.life++;
                System.out.println(this.name + "回复了1点体力...");
                this.holdCards.remove(useCard);
                throwCards.add(useCard);


                if (useCard.getBrandName().equals("酒")) {
                    wineCount++;
                }

                if (this.life <= 0) {
                    if (wineCount < 1)
                        System.out.println(this.name + "当前体力为" + this.life + ",还需要" + (1 - this.life) + "个桃或酒");
                    else
                        System.out.println(this.name + "当前体力为" + this.life + ",还需要" + (1 - this.life) + "个桃");
                    continue;
                } else {
                    System.out.println(this.name + "脱离了濒死状态");
                    break;
                }
            }
        } while (this.hasPeaches() || this.hasWines());
        return !(this.life <= 0);
    }

    /**
     * 武将是否有桃的方法
     *
     * @return true-有 false-没有
     */
    protected boolean hasPeaches() {
        for (HolderCard h : this.holdCards) {
            if ("桃".equals(h.getBrandName()))
                return true;
        }
        return false;
    }

    /**
     * 武将是否有酒的方法
     *
     * @return true-有 false-没有
     */
    protected boolean hasWines() {
        for (HolderCard h : this.holdCards) {
            if ("酒".equals(h.getBrandName()))
                return true;
        }
        return false;
    }

    /**
     * 武将是否有闪的方法
     *
     * @return true-有 false-没有
     */
    protected boolean hasShans() {
        for (HolderCard h : this.holdCards) {
            if ("闪".equals(h.getBrandName()))
                return true;
        }
        return false;
    }

    /**
     * 描述武将状态的方法
     *
     * @param showWeapon 是否显示武器 true-显示 false-不显示
     * @return 武将状态描述信息
     */
    public String heroDesc(boolean showWeapon) {
        StringBuilder sb = new StringBuilder();
        if (showWeapon)
            sb.append(this).append("\t武器==>" + (CommonUtil.isEmpty(this.weapon) ? "" : this.weapon))
                    .append("\t防具==>" + (CommonUtil.isEmpty(this.armor) ? "" : this.armor)).append("\t坐骑==>" + this.horsesDesc());
        else
            sb.append(this).append("\t防具==>" + (CommonUtil.isEmpty(this.armor) ? "" : this.armor))
                    .append("\t坐骑==>" + this.horsesDesc());
        return sb.toString();
    }

    private String horsesDesc() {
        StringBuilder sb = new StringBuilder();
        for (HorseCard h : this.horses) {
            if (CommonUtil.isNotEmpty(h))
                sb.append(h.getBrandName()).append(h.getRange() + "马,");
        }
        if (sb.length() != 0)
            return "【" + sb.substring(0, sb.length() - 1) + "】";
        return "【】";
    }

    /**
     * 武将是否有+1或者-1坐骑
     *
     * @param range 1--+1马 -1---减一马
     * @return 加一或者减一马的对象
     */
    public HorseCard hasOneHorse(int range) {
        for (HorseCard h : this.horses) {
            if (range == 1) {
                if (h.getRange() == 1)
                    return h;
            } else if (range == -1) {
                if (h.getRange() == -1)
                    return h;
            }
        }
        return null;
    }

    /**
     * 武将每回合开始
     * 按顺序执行每一个阶段
     *
     * @param cards       摸牌堆
     * @param throwCards  弃牌堆
     * @param aliveHeroes 存活的武将
     * @param sc
     */
    public void excuteAction(LinkedList<HolderCard> cards, LinkedList<HolderCard> throwCards, LinkedList<BaseHero> aliveHeroes, Scanner sc) throws BaseException {
        //准备阶段
        excutePreparationStage();
        //判定阶段
        excuteDecisionStage(cards, throwCards, aliveHeroes, sc);
        //摸牌阶段
        excuteTouchStage(cards);
        //出牌阶段
        excutePlayingStage(sc, aliveHeroes, throwCards);
        //弃牌阶段
        excuteDiscardStage(throwCards, sc);
        //结束阶段
        excuteEndStage();
    }

    /**
     * 调用准备阶段
     */
    protected void excutePreparationStage() {

    }

    /**
     * 调用判定阶段
     *
     * @param cards
     * @param throwCards
     * @param aliveHeroes
     * @param sc
     */
    protected void excuteDecisionStage(LinkedList<HolderCard> cards, LinkedList<HolderCard> throwCards, LinkedList<BaseHero> aliveHeroes, Scanner sc) {

        if (CommonUtil.isNotEmpty(this) && CommonUtil.isNotEmpty(this.getYanShiArea())) {

            int forechCount = this.getYanShiArea().size();
            for (int i = 0; i < forechCount; i++) {
                YanShiJinNangCard ysjn = this.getYanShiArea().pop();
                //取出牌堆顶的判定牌
                HolderCard pdCard = CommonUtil.getPdCard(cards);
                System.out.println(this.getName() + "的判定结果为" + pdCard.toString());
                if ("乐不思蜀".equals(ysjn.getBrandName())) {
                    //与对应点数做判断
                    if ("♡".equals(pdCard.getDecor())) {
                        System.out.println(this.getName() + "的乐不思蜀判定失效");
                    } else {
                        System.out.println(this.getName() + "的乐不思蜀判定生效");
                        lbssFlg = true;
                    }
                    //将判定牌置入弃牌堆
                    throwCards.add(pdCard);
                } else if ("兵粮寸断".equals(ysjn.getBrandName())) {
                    //与对应点数做判断
                    if ("♣".equals(pdCard.getDecor())) {
                        System.out.println(this.getName() + "的兵粮寸断判定失效");
                    } else {
                        System.out.println(this.getName() + "的兵粮寸断判定生效");
                        blcdFlg = true;
                    }
                    //将判定牌置入弃牌堆
                    throwCards.add(pdCard);
                } else if ("闪电".equals(ysjn.getBrandName())) {
                    //与对应点数做判断
                    if (!("♤".equals(pdCard.getDecor()) && (pdCard.getPoint() >= 2 && pdCard.getPoint() <= 9))) {
                        System.out.println(this.getName() + "的闪电判定失效");
                    } else {
                        System.out.println(this.getName() + "的闪电判定生效");
                        this.takeDamage(3, aliveHeroes, sc, throwCards);
                    }
                    //将判定牌置入弃牌堆
                    throwCards.add(pdCard);
                }
            }
            forechCount = this.getYanShiArea().size();
        }
    }


    /**
     * 调用摸牌阶段
     *
     * @param cards
     */
    protected void excuteTouchStage(LinkedList<HolderCard> cards) {
        if (!blcdFlg) {
            CommonUtil.getCards(cards, this, this.getGetCardsCount());
        }
        blcdFlg = false;
    }

    /**
     * 调用出牌阶段
     *
     * @param sc
     * @param aliveHeroes
     * @param throwCards
     */
    protected void excutePlayingStage(Scanner sc, LinkedList<BaseHero> aliveHeroes, LinkedList<HolderCard> throwCards) throws BaseException {
        if (!lbssFlg) {
            while (true) {
                System.out.println(this.getName() + "的手牌为===>" + CommonUtil.showCardsName(this.getHoldCards()));
                System.out.print("是否要结束出牌(1-结束,0-不结束):");
                String index = sc.nextLine();
                if (Integer.valueOf(index) == 1)
                    break;
                CommonUtil.getAliveHeroNames(aliveHeroes, this, true);
                System.out.println("请输入您需要使用的牌,顺序(从1到n),例如:1");
                System.out.print("请输入:");
                index = sc.nextLine();
                HolderCard useCard = this.getHoldCards().get(Integer.valueOf(index) - 1);
                //基本牌
                if (useCard instanceof BasicCard) {
                    if (useCard.getBrandName().contains("杀")) {
                        //判断还能不能出杀了
                        if (this.checkShaCount()) {
                            //被杀的武将
                            BaseHero h;
                            endpoint1:
                            while (true) {
                                System.out.println("请输入杀选择的目标,例如:张飞");
                                System.out.print("请输入:");
                                index = sc.nextLine();
                                for (BaseHero aliveHero : aliveHeroes) {
                                    if (aliveHero.getName().equals(index)) {
                                        h = aliveHero;
                                        break endpoint1;
                                    }
                                }
                            }
                            h.beiSha(this, aliveHeroes, sc, throwCards, useCard);
                            this.shaCount++;
                        }
                    } else if (useCard.getBrandName().equals("桃")) {
                        if (this.getLife() >= this.getMaxLife()) {
                            System.out.println("您无需吃桃回血!");
                        } else {
                            this.setLife(this.getLife() + 1);
                            System.out.println(this.getName() + "使用" + useCard + "回复了1点体力!");
                            System.out.println(this.getName() + "当前体力值==>" + this.getLife());
                            this.getHoldCards().remove(useCard);
                            throwCards.add(useCard);
                        }
                    } else if (useCard.getBrandName().equals("酒")) {
                        if (this.getUseWinesCount() > 1) {
                            System.out.println("您已经使用酒了,无法继续使用!");
                            continue;
                        } else {
                            this.getHoldCards().remove(useCard);
                            this.setUseWinesCount(this.getUseWinesCount() + 1);
                            System.out.println(this.getName() + "使用了" + useCard);
                        }
                    }
                }
                //武器牌
                if (useCard instanceof WeaponCard) {
                    if (CommonUtil.isEmpty(this.getWeapon())) {
                        this.getHoldCards().remove(useCard);
                        this.setWeapon((WeaponCard) useCard);
                        System.out.println(this.getName() + "对自己使用" + useCard);
                    } else {
                        System.out.println(this.getName() + "的" + this.getWeapon() + "被弃置...");
                        throwCards.add(this.getWeapon());
                        this.getHoldCards().remove(useCard);
                        this.setWeapon((WeaponCard) useCard);
                        System.out.println(this.getName() + "对自己使用" + useCard);
                    }
                }
            }
            this.setShaCount(0); //重置武将出杀的个数
        }
        lbssFlg = false;
    }

    /**
     * 调用弃牌阶段
     *
     * @param throwCards
     * @param sc
     */
    protected void excuteDiscardStage(LinkedList<HolderCard> throwCards, Scanner sc) {
        while (this.getHoldCards().size() > this.getLife()) {
            System.out.println(this.getName() + "的手牌为===>" + CommonUtil.showCardsName(this.getHoldCards()));
            System.out.println(this.getName() + "还需要弃置" + (this.getHoldCards().size() - this.getLife()) + "张牌");
            System.out.println("请输入您需要弃牌的顺序(从1到n),例如:1,3,4");
            System.out.print("请输入:");
            String index = "";
            index = sc.nextLine();
            String[] indexs = index.split(",");

            if (indexs.length != (this.getHoldCards().size() - this.getLife())) {
                System.out.println("弃置牌的数量不符合规定!");
                continue;
            }

            List<HolderCard> tempList = new ArrayList<>();
            for (String ind : indexs) {
                throwCards.add(this.getHoldCards().get(Integer.valueOf(ind) - 1));
                tempList.add(this.getHoldCards().get(Integer.valueOf(ind) - 1));
                System.out.println(this.getName() + "的" + throwCards.getLast() + "被弃置...");
            }

            this.getHoldCards().removeAll(tempList);
            System.out.println(this.getName() + "的手牌为===>" + CommonUtil.showCardsName(this.getHoldCards()));
        }
    }

    /**
     * 调用结束阶段
     */
    protected void excuteEndStage() {

    }

    /**
     * 检查出杀的次数
     *
     * @return true--可以出杀  false--不能出杀
     */
    protected boolean checkShaCount() {
        //出杀前判断发动诸葛连弩
        if (CommonUtil.isNotEmpty(this.weapon))
            return (boolean) CommonUtil.weaponFunction(this.weapon, this, null, null, null, null);

        if (this.maxSha <= this.shaCount) {
            System.out.println("本阶段不能再使用杀了...");
            return false;
        }
        return true;
    }
}
